#include    "unp.h"
#include    <linux/netfilter_ipv4/ip_tables.h>
#include <string.h> /* memset(), memcpy() */
#include <arpa/inet.h>


const int BACK_LOG = 5;

void getIpByName(char *deviceName, struct in_addr* netAddr) {
    int fd;
    struct ifreq ifr;

    fd = socket(AF_INET, SOCK_DGRAM, 0);

    /* I want to get an IPv4 IP address */
    ifr.ifr_addr.sa_family = AF_INET;

    /* I want IP address attached to "eth0" */
    strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);

    ioctl(fd, SIOCGIFADDR, &ifr);

    close(fd);

    *netAddr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
}

int main(int argc, char **argv) {
    int status = 0;
    int serverSocket = 0;
    int port = 18190;
//    uint32_t ipAddr;

    struct in_addr ipAddr;

    // struct ifaddrs *ifaddr, *ifa;

    struct hostent *hostPtr = NULL;
    char hostname[80] = "";
    char devicename[30] = "";
    struct sockaddr_in serverInfo;

    struct sockaddr_in originDst  = { 0 };
    socklen_t sin_size = sizeof(originDst);

    if (2 != argc) {
        fprintf(stderr, "Usage: %s netDeviceName\n",
                argv[0]);
        exit(1);
    }

    status = gethostname(hostname,
                         sizeof(hostname));
    if (-1 == status)
    {
        perror("gethostname()");
        exit(1);
    }

    hostPtr = gethostbyname(hostname);
    if (NULL == hostPtr)
    {
        perror("gethostbyname()");
        exit(1);
    }

    (void) memset(&devicename, 0,
                  sizeof(devicename));
    (void) strcpy(devicename, argv[1]);

    printf("netDeviceName:%s\n", devicename);

    getIpByName(devicename, &ipAddr);
    printf("ipAddr:%d\n", ipAddr.s_addr);
    char *strAddr = inet_ntoa(ipAddr);
    printf("netStrAddr:%s\n", strAddr);

    // port = atoi(argv[1]);

    serverSocket = socket(PF_INET, SOCK_STREAM,
                          IPPROTO_TCP);
    if (-1 == serverSocket) {
        perror("socket()");
        exit(1);
    }

    (void) memset(&serverInfo, 0,
                  sizeof(serverInfo));
    (void) memcpy(&serverInfo.sin_addr,
                  hostPtr->h_addr,
                  hostPtr->h_length);

    serverInfo.sin_addr.s_addr = ipAddr.s_addr;
    serverInfo.sin_family = AF_INET;
    serverInfo.sin_port = htons(port);
    status = bind(serverSocket,
                  (struct sockaddr *) &serverInfo,
                  sizeof(serverInfo));
    if (-1 == status) {
        perror("bind()");
        exit(1);
    }
    status = listen(serverSocket, BACK_LOG);
    if (-1 == status) {
        perror("listen()");
        exit(1);
    }


    for (;;) {
        int slaveSocket;
        struct sockaddr_in clientName = { 0 };
        socklen_t clientLength =
                sizeof(clientName);

        (void) memset(&clientName, 0,
                      sizeof(clientName));
        slaveSocket = accept(serverSocket,
                             (struct sockaddr *) &clientName,
                             &clientLength);
        printf("accepting\n");
        if(getsockopt(slaveSocket, SOL_IP, SO_ORIGINAL_DST, &originDst, &sin_size) == 0){
            printf("new connection:%s,%u",inet_ntoa(clientName.sin_addr),ntohs(clientName.sin_port));
            printf("->%s,%u\n",inet_ntoa(originDst.sin_addr),ntohs(originDst.sin_port));
        }else{
            printf("ELSE\n");
            perror("getsockopt SO_ORIGINAL_DST:");
        }

        printf("getsockopting\n");
    }
}
